fix(coding-agent): keep host credentials out of the kernel and its state snapshots - #2174
fix(coding-agent): keep host credentials out of the kernel and its state snapshots#2174kevinjosethomas wants to merge 1 commit into
Conversation
…its snapshots Spawn the REPL kernel with an allowlisted environment instead of the full host environment, skip snapshotting names that hold a known host credential value, add --no-kernel-snapshots / kernel.stateSnapshots to disable kernel state persistence, and create session transcripts owner-only. Linear: ENG-5342
Prime Agent performance — completedPR
Python runtime
Sandbox cost: ~$0.0876 — no inference calls. Methodology and samplesMain resolved at 2026-09-09T23:53:56.704948+00:00. Harness
|
Context
Linear: ENG-5342 — https://linear.app/primeintellect/issue/ENG-5342
Root cause:
ReplKernelManager.doStartspawned the REPL kernel with{ ...process.env, ...options.env }, so every host credential (PRIME_API_KEY,OPENAI_API_KEY, ...) was readable from kernel andbash()cells viaos.environ. Anything the model assigned from it was pickled by the per-session snapshot intosession-artifacts/<id>/kernel-state.dilland revived on resume, so scrubbing the (0644) transcript did not remove it. There was no redaction and no way to turn snapshots off.Changes
src/core/kernel/kernel-env.ts). The kernel receives an allowlisted subset of the host env (PATH/HOME/locale/TMP/terminal/proxy/TLS/toolchain homes,RLM_*,PRIME_AGENT_*,PYTHON*,UV_*,PIP_*,LC_*,XDG_*,GIT_*, the Windows system set) plus what the session injects (RLM_*,PRIME_AGENT_BASH_*,SERPER_API_KEYwhen the websearch skill is loaded — now handed over explicitly instead of relying on inheritance). Names that denote credentials (theenv-api-keys.ts/prime-agent.sh --no-envlist,*_API_KEY,*_TOKEN,*SECRET*,*PASSWORD*, AWS/GCP ambient credential vars) are dropped even under an allowed prefix and listed in the kernel diagnostics.kernel.envPassthrough(settings) admits extra names orPREFIX*globs.bash()children inherit the kernel env, so they see the same set.--no-kernel-snapshots(CLI, also accepted byprime-agent daemon session) orkernel.stateSnapshots: false(settings) disables writing and restoringkernel-state.dillfor the session while keeping the kernel stderr log. New transcripts (sessions/<id>.jsonl, forks) are created 0600; existing files keep their mode.snapshotrequest asredact_sha256; the runtime skips top-levelstr/bytesnames whose digest (or the stripped form's) matches and reports them inskipped/kernel-state.jsonwith reasonmatches a credential from the host environment. The kernel never receives the values.Docs: settings.md (Kernel section), usage.md, sessions.md, rlm-runtime.md, README,
repl.mdprotocol, prime-intellect inference reference. Model-facing surface unchanged (tool names, system prompt,rlmAPI); the host-onlysnapshotprotocol request gains an optional field.Behaviour note: kernel code that relied on inheriting
PRIME_API_KEY(e.g. direct Prime Inference calls) must read~/.prime/config.jsonor opt in viakernel.envPassthrough; theprimeCLI is unaffected.Validation
Local (macOS):
npm run checkclean.test/kernel-env.test.ts,ipython-provisioner,session-manager/file-operations,session-manager-flush,agent-session-config,settings-manager,kernel-state-snapshot,kernel-bash-shell,kernel-windows-process,args,daemon-command,main-interactive-routing: pass.repl-kernel-*.test.tsincl. newrepl-kernel-secret-retention.test.ts(with--tagsFilter kernel-heavy): pass.pytest test/test_repl.py: 106 passed.Prime sandbox (
node:24-bookworm, usertester, synthetic keys only), fixtureeng5342-check.tsrun on main @ 427ea4c and on this branch with each tree's own runtime venv:os.environ['PRIME_API_KEY']in a cellNoneOPENAI_API_KEY, PRIME_API_KEYsh -c 'echo $PRIME_API_KEY'from the kernelunsetlauncher_key = <key>matches a credential from the host environment); dill contains neitherlauncher_keyNone(other names restored)sessions/<id>.jsonl/ fork modestateSnapshots: falseBranch tests in the sandbox: kernel-heavy files 4/4 pass (
repl-kernel-secret-retention,state-roundtrip,mcp-shutdown,parent-watchdog),test_repl.py106 passed, 16/17 unit files pass. The one failing file,resource-loader.test.ts(4 symlinked-extension tests), fails identically on unpatched main in the same sandbox: pre-existing, unrelated.Not validated: Windows (env-name case handling covered by unit tests only); the daemon-worker path was exercised through the shared
createAgentSessionFromServiceswiring, not a live daemon.